/********************************************************************************
*                 Copyright (C) 2011 - Las Venturas Playground                  *
*                      http://sa-mp.nl | http://lvp-iv.com                      *
*                                                                               *
*    This program is free software: you can redistribute it and/or modify       *
*    it under the terms of the GNU General Public License as published by       *
*    the Free Software Foundation, either version 3 of the License, or          *
*    (at your option) any later version.                                        *
*                                                                               *
*    This program is distributed in the hope that it will be useful,            *
*    but WITHOUT ANY WARRANTY; without even the implied warranty of             *
*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the              *
*    GNU General Public License for more details.                               *
*                                                                               *
*    You should have received a copy of the GNU General Public License          *
*    along with this program.  If not, see <http://www.gnu.org/licenses/>.      *
*                                                                               *
*********************************************************************************
*                                                                               *
*   Las Venturas Playground - Minigames/minigameInterfaces.nut                  *
*                                                                               *
*   This file contains the minigame interfaces. Every minigame type is made     *
*   up of 2 classes - a Definition and an Instance. A Definition is simply a    *
*   set of variables containing things like spawn points, weapons, time limits, *
*   and so on. Instances are where the actual magic happens, processing events  *
*   and making decisions based on the Definition that was provided.             *
*   When writing your own minigame handler, you'll want to create your own      *
*   Instance class inheriting from the Instance interface, implementing new     *
*   logic by overriding any of the empty callbacks.
*                                                                               *
*   Author:                                                                     *
*   Pugwipe <pugwipe@gmail.com>                                                 *
*                                                                               *
********************************************************************************/


/* 
 * Class: Minigames.Definition.Base
 * This is the minigame definition class. Not that much to it, it's just a set of 
 * variables and get/set functions. Can be extended.
 */
class Minigames.Definition.Base
{
    /*
     * constructor
     * Initializes some default values
     */
    constructor ()
    {
        this.spawnInfo = [];
        this.setMaxSignupTime (30);
        this.setMinSignups (2);
        this.setMaxPlayers (null);
        this.setEntranceFee (500);
        this.setTimeLimit (null);
        this.setTeamNumber (1);
        this.setMaxInstances (1);    
        this.setMinigameName ("Unnamed Minigame");
        this.setCommand (null);
    }
   
    /* 
     * Method: addSpawnPoint ()
     * Sets spawn point info for this minigame.
     *
     * @param spawnInfo  Object containing information about the spawn point. This includes 
     *                   the position, rotation, and possibly vehicles and weapons.
     */
    function addSpawnPoint (spawnInfo)
    {
        this.spawnInfo.append (spawnInfo);
    }
    
    /* 
     * Method: setMaxPlayers ()
     * Sets the max. player number for this minigame.
     *
     * @param maxPlayers  Max. player number.
     */
    function setMaxPlayers (maxPlayers)
    {
        this.maxPlayers = maxPlayers;
    }
    
    /* 
     * Method: setTeamNumber ()
     * Sets the number of teams for this minigame.
     *
     * @param numTeams  The number of teams. Set this to 1 for a free-for-all.
     */
    function setTeamNumber (numTeams)
    {
        this.numTeams = numTeams;
    }
    
    /* 
     * Method: setMaxSignupTime ()
     * Sets the maximum duration of the signup period.
     * 
     * @param maxTime  Max. signup duration in seconds.
     */
    function setMaxSignupTime (maxTime)
    {
        this.maxSignupTime = maxTime;
    }
    
    /* 
     * Method: setMinSignups ()
     * Sets the minimum number of signups required for this minigame to start.
     *
     * @param minSignups  Minimum number of players that have to enter this minigame.
     */
    function setMinSignups (minSignups)
    {
        this.minSignups = minSignups;
    }
   
    /* 
     * Method: setTimeLimit ()
     * Sets the time limit for this minigame.
     *
     * @param timeLimit  The time limit for this minigame, in seconds. Set to null for no time limit.
     */
    function setTimeLimit (timeLimit)
    {
        this.timeLimit = timeLimit;
    }
    
    /* 
     * Method: setMaxInstances ()
     * How many instances of this minigame can run simultaneously?
     * Because of the absence of dimensions/virtual worlds in IV:MP, this should always be 1.
     *
     * @param maxInstances  The max. number of instances this minigame supports.
     */
    function setMaxInstances (maxInstances)
    {
        this.maxInstances = maxInstances;
    }
    
    /*
     * Method: setMinigameName ()
     * Sets the minigame name.
     *
     * @param minigameName  A string containing the name of this minigame.
     */
    function setMinigameName (minigameName)
    {
        this.minigameName = minigameName;
    }
    
    /* 
     * Method: setEntranceFee ()
     * Sets the entrance fee for this minigame.
     *
     * @param entranceFee  How much money does signing up cost?
     */
    function setEntranceFee (fee)
    {
        this.entranceFee = fee;
    }
    
    /*
     * Method: setCommand ()
     * Sets the trigger command for this minigame.
     *
     * @param command  String containing the trigger command.
     */
    function setCommand (command)
    {
        this.command = command;
    }
    
    
    /* Start of getter functions */    
    
    /*
     * Method: getSpawnInfo ()
     * Gets information about the spawn points.
     *
     * @return  An array of Minigame.SpawnInfo objects that are associated with this minigame.
     */     
    function getSpawnInfo () 
    { 
        return this.spawnInfo; 
    }
    
    /*
     * Method: getMaxSignupTime ()
     *  
     * @return  Max duration of the signup period in seconds.
     */
    function getMaxSignupTime () 
    {
        return this.maxSignupTime; 
    }
    
    /*
     * Method: getMinSignups ()
     * 
     * @return  The minimum amount of signups required for this minigame to start.
     */
    function getMinSignups ()
    {
        return this.minSignups; 
    
    }
    
    /* 
     * Method: getMaxPlayers ()
     * 
     * @return  The maximum amount of players allowed to enter this minigame.
     */
    function getMaxPlayers ()
    { 
        return this.maxPlayers; 
    }
    
    /* 
     * Method: getEntranceFee ()
     *
     * @return  The entrance fee players have to pay upon signup.
     */
    function getEntranceFee ()
    {
        return this.entranceFee; 
    }
    
    /* 
     * Method: getTimeLimit ()
     *
     * @return  The time limit for this minigame, in seconds.
     */     
    function getTimeLimit ()
    {
        return this.timeLimit; 
    }
    
    /* 
     * Method: getTeamNumber ()
     * 
     * @return  The number of teams for this minigame.
     */
    function getTeamNumber ()
    {
        return this.numTeams; 
    }
    
    /*
     * Method: getMaxInstances ()
     *
     * @return  The maximum amount of simultaneous instances this minigame supports.
     */
    function getMaxInstances ()
    {
        return this.maxInstances; 
    }
    
    /*
     * Method: getMinigameName ()
     *
     * @return  The name of this minigame.
     */    
    function getMinigameName () 
    {
        return this.minigameName; 
    }
    
    /*
     * Method: getCommand ()
     *
     * @return  The trigger command.
     */
    function getCommand ()
    {
        return this.command;
    }
    
    /*
     * Method: formatStartMessage ()
     * Formats the message that is displayed when this minigame starts and returns
     * it as a string. This method can of course be overloaded in derived classes.
     *
     * @return  A string containing the start message.
     */
    function formatStartMessage ()
    {
        return "The " + this.getMinigameName () + " minigame has started! Type " + this.getCommand () + " to sign up.";
    }
    
   
    /* data members */
    spawnInfo = null;    
    maxSignupTime = 30;
    minSignups = 2;
    maxPlayers = 0;
    entranceFee = 500;    
    timeLimit = null;
    numTeams = 1;
    maxInstances = 1;    
    minigameName = "Unnamed Minigame";
    command = null;
}

// Minigame states
Minigames.State <- 
{
    Idle = "idle",
    Registering = "registering",
    Running = "running"
};

// Minigame end reasons
Minigames.EndReason <-
{
    Finished = "finished",
    TimeExpired = "time limit expired",
    NotEnoughSignups = "not enough signups"
};


/*
 * Class: Minigames.Instance.Base
 * This is the minigame Instance class. Every instance of this class represents
 * a currently running minigame. Its functionality can and should be extended by 
 * implementing any of the callbacks.
 */
class Minigames.Instance.Base 
{
    /*
     * constructor
     *
     * @param minigameDefinition  Instance of a Minigame.Definition.Base class
     *                            or a class that inherits from it.
     */
    constructor (minigameDefinition)
    {
        this.minigameDefinition = minigameDefinition;
        this.createdVehicles = [];
        this.joinedPlayers = [];
        this.setMinigameState (Minigames.State.Registering);
        this.savedPlayerStates = {};
        this.playerMinigameStates = [];
        
        this.startTime = getTickCount ();
    }
    
    /* 
     * Method: startMinigame ()
     * The signup period is over! Let's start the minigame.
     */
    function startMinigame ()
    {
        if (this.joinedPlayers.len () < this.minigameDefinition.getMinSignups ()) 
        {
            this.endMinigame (Minigames.EndReason.NotEnoughSignups);
            return;
        }
        
        sendMessageToAll ("Minigame " + minigameDefinition.getMinigameName () + " started!");
        
        // Let's shuffle the player order
        arrayShuffle (this.joinedPlayers);
        
        // Spawn all players
        this.spawnAllPlayers ();
        
        // And update the state
        this.setMinigameState (Minigames.State.Running);
        
        this.startTime = getTickCount ();
    }
    
    /*
     * Method: setMinigameState ()
     * Sets the state of the minigame.
     *
     * @param state  The new state, a member of the Minigames.State table.
     */
    function setMinigameState (state)
    {
        local oldState = this.state;
        this.state = state;        
        if (state != oldState) this.onMinigameStateChange (oldState, state);
    }
    
    /*
     * Method: spawnAllPlayers ()
     * Simply spawns all players on the default positions, and saves their states.
     */
    function spawnAllPlayers ()
    {
        foreach (i, playerid in this.joinedPlayers)
        {
            this.savePlayerState (i);
			this.setPlayerMinigameState(i, Minigames.State.Running);
            this.spawnPlayer (i, i);            
        }
    }
    
    /*
     * Method: sendMessageToParticipants
     * Sends a message to all participants, whether they're dropped out or not.
     */     
    function sendMessageToParticipants (message)
    {
        foreach (i, playerid in this.joinedPlayers)
        {
            if (!isPlayerConnected (playerid)) continue;
            
            sendPlayerMessage (playerid, message);
        }
    }
    
    /*
     * Method: sendMessageToActiveParticipants
     * Sends a message to all participants who are still playing the minigame.
     */
    function sendMessageToActiveParticipants (message)
    {
        foreach (i, playerid in this.joinedPlayers)
        {
            if (!isPlayerConnected (playerid)) continue;
            if (this.getPlayerMinigameState (playerid) != Minigames.State.Running) continue;
            
            sendPlayerMessage (playerid, message);
        }
    }
    
    /* Method: spawnPlayer ()
     * Spawns a player at a given spawn point.
     *
     * @param id  The ID this minigame uses for a player INTERNALLY. 
     *            Note that this is not their actual playerid.
     *
     */
    function spawnPlayer (id, pointID = null)
    { 
        if (pointID == null) pointID = id;
        
        local playerid = this.joinedPlayers[id];       
        local spawnInfoLength = this.minigameDefinition.spawnInfo.len();
		local randomNumber = random (0, (spawnInfoLength - 1));
		local spawnInfo = this.minigameDefinition.spawnInfo[randomNumber];

        local pos = spawnInfo.spawnPos;
        local rotation = spawnInfo.spawnRotation;
        
        local vehicle = spawnInfo.spawnVehicle;
        
        if (vehicle != null) 
        {
            // The player spawns in a vehicle
            local vehID = createMinigameVehicle (vehicle[0], pos[0], pos[1], pos[2], rotation, vehicle[2], vehicle[3], vehicle[4], vehicle[5]);
            warpPlayerIntoVehicle (playerid, vehID, vehicle[1]);
        }
        
        else 
        {
            // The player doesn't spawn in a vehicle
            setPlayerCoordinates (playerid, pos[0], pos[1], pos[2]);
            setPlayerHeading (playerid, rotation.tofloat());
            setCameraBehindPlayer ( playerid );
        }
        
        // Let's give them their spawn weapons, shall we?       
        // Remove all weapons they currently possess
        removePlayerWeapons (playerid);
        
        local weapons = spawnInfo.spawnWeapons;
        
        // Just loop through the table
        foreach (weaponID, ammo in weapons) 
        {
            // And give the weapon to the player
            givePlayerWeapon (playerid, weaponID, ammo);
        }
    }
    
    /*
     * Method: savePlayerState ()
     * Saves the state of a player before spawning them in a minigame, so that
     * they can be sent back to the same position when the minigame is finished.
     *
     * @param playerid  The player ID of the player.
     */
    function savePlayerState (playerid) 
    {
        local pos = getPlayerCoordinates (playerid);
        local rotation = getPlayerHeading (playerid);
        local armor = getPlayerArmour (playerid);
        local health = getPlayerHealth (playerid);
        
        // TODO: weapons
        this.savedPlayerStates[playerid] <- 
        {
            pos = pos,
            rotation = rotation,
            armor = armor,
            health = health
        };
    }
    
    /*
     * Method: loadPlayerState ()
     * After a minigame is finished, this method loads a player's saved state and restores it.
     *
     * @param playerid  The player ID.
     */
    function loadPlayerState (playerid) 
    {
        if (!(playerid in this.savedPlayerStates)) return;
        if (!isPlayerSpawned (playerid)) return;
        
        local pos = this.savedPlayerStates[playerid].pos;
        local rotation = this.savedPlayerStates[playerid].rotation;
        local armor = this.savedPlayerStates[playerid].armor;
        local health = this.savedPlayerStates[playerid].health;
        
        setPlayerCoordinates (playerid, pos[0], pos[1], pos[2]);
        setPlayerHeading (playerid, rotation);
        setPlayerArmour (playerid, armor);
        setPlayerHealth (playerid, health);
    }
    
    /*
     * Method: createMinigameVehicle ()
     * Creates a vehicle for use in this minigame.
     * Same parameters as IV:MP's createVehicle().
     */
    function createMinigameVehicle (model, posX, posY, posZ, heading, c1 = 0, c2 = 0, c3 = 0, c4 = 0)
    {
        local vehID = createVehicle (model, posX, posY, posZ, heading, c1, c2, c3, c4);
        this.createdVehicles.append (vehID);
    }
    
    /* 
     * Method: endMinigame ()
     * Ends the minigame with the reason specified, and passes it on
     * to the minigame core handler.
     *
     * @param reason  The end reason, a member of the Minigames.EndReason table.
     */
    function endMinigame (reason = Minigames.EndReason.Finished)
    {
        Minigames.Core.endMinigame (this, reason);
        
        foreach (playerid in this.joinedPlayers) 
        {
            this.loadPlayerState (playerid);
        }
        
        if (reason == Minigames.EndReason.NotEnoughSignups)
        {
            local minigameName = this.getDefinition ().getMinigameName ();
            
            foreach (playerid in this.joinedPlayers)
            {
                givePlayerMoney (playerid, this.getDefinition ().getEntranceFee ());
                sendPlayerMessage (playerid, "There were not enough signups for the " + minigameName + "!");
                sendPlayerMessage (playerid, "Your entrance fee has been refunded.");
            }
        }
		
		else if(reason == Minigames.EndReason.TimeExpired)
		{
			local minigameName = this.getDefinition ().getMinigameName ();

			foreach (playerid in this.joinedPlayers)
            {
				sendPlayerMessage (playerid, "Nobody won the " + minigameName + " minigame, the time expired.");
			}
		}
		
		this.setMinigameState (Minigames.State.Idle);
    }
    
    /*
     * Method: getPlayersInMinigame ()
     * Gets the players still playing this minigame.
     *
     * @return  An array containing the player IDs playing this minigame.
     */
    function getPlayersInMinigame ()
    {
        local result = [];
        foreach (i, playerid in this.joinedPlayers)
        {
            if (this.getPlayerMinigameState (playerid) == Minigames.State.Running)
            {
                result.append (playerid);
            }
        }
        
        return result;
    }
    
    /*
     * Method: getElapsedTime ()
     * Gets the time elapsed since the minigame started.
     *
     * @return  The time elapsed since the minigame started, in milliseconds.
     */       
    function getElapsedTime ()
    {
        if (this.startTime == null) return 0;
        
        local time = ::getTickCount () - this.startTime;
        if (time < 0) time += 0x7FFFFFFF; // For overflows
        
        return time;
    }
    
    /* 
     * Method: signUpForMinigame ()
     * Signs a player up for this minigame. Since the minigame core handler is in charge of this,
     * this method should never be called from anywhere else.
     *
     * @param playerid  The player ID.
     */
    
    function signPlayerUp (playerid)
    {
        if (!isPlayerConnected (playerid)) return false;
        
        local fee = this.getDefinition ().getEntranceFee ();
        if (getPlayerMoney (playerid) < fee)
        {
            sendPlayerMessage (playerid, "You don't have enough money for the " + this.getDefinition ().getMinigameName () + "!");
            sendPlayerMessage (playerid, "Signing up costs $" + fee + ".");
            return false;
        }
		  
        local playerFound = false;
        foreach (id in this.joinedPlayers)
        {
            if (id == playerid) 
            {
                playerFound = true;
                sendPlayerErrorMessage (playerid, "You have already signed up for the " + this.getDefinition ().getMinigameName () + "!");
            }
        }
        
        if(!playerFound)
        {
            sendPlayerMessage (playerid, "You have signed up for the " + this.getDefinition ().getMinigameName () + "!");
            givePlayerMoney (playerid, -fee);
            
			this.joinedPlayers.append (playerid);
			
			this.playerMinigameStates.append (playerid);
			this.setPlayerMinigameState(playerid, Minigames.State.Registering);
			this.onPlayerSignUp (playerid);
            
            // If max. players have been reached...
            if (this.joinedPlayers.len () >= this.getDefinition ().getMaxPlayers ()) 
            {
                // ...start the minigame
                this.startMinigame ();
            }
        }
        return true;
    }
    
    /* 
     * Method: endForPlayer ()
     * Ends the minigame for a player.
     *
     * @param playerid  The player ID.
     */
    function endForPlayer (playerid)
    {
        if (this.areSignupsAllowed ()) 
		{
            foreach (i, id in this.joinedPlayers)
            {
                if (id != playerid) continue;
                
                this.joinedPlayers.remove (i);
				this.playerMinigamesStates.remove (i);
            }
        }
        
        else 
		{
            this.loadPlayerState (playerid);
			this.setPlayerMinigameState (playerid, Minigames.State.Idle);				
            this.onPlayerFinish (playerid);    			
        }
    }
    
    function setPlayerMinigameState (playerid, state)
    {
	    foreach (i, id in this.joinedPlayers)
        {
			if (id != playerid) continue;
                
            this.playerMinigameStates[i] = state;
        }
    }
    
    function getPlayerMinigameState (playerid)
    {
	    foreach (i, id in this.joinedPlayers)
        {
			if (id != playerid) continue;
                
            return this.playerMinigameStates[i];
        }
        return null;
    }
    
    function areSignupsAllowed ()
    {
        return this.state == Minigames.State.Registering;
    }
    
    /* 
     * Method: isPlayerPlayingThisMinigame ()
     *
     * @param  playerid  The player ID.
     *
     * @return  Whether the player ID is registerd with this minigame.
     */
    function isPlayerPlayingThisMinigame (playerid)
    {
        if (!isPlayerConnected ()) return false;
        
        foreach (id in this.joinedPlayers) 
        {
            if (id == playerid) return true;
        }
        
        return false;
    }
    
    /*
     * Method: getState ()
     * 
     * @return  The state of this minigame, a member of the Minigames.State table.
     */
    function getState ()
    {
        return this.state;
    }
    
    /*
     * Method: getDefinition ()
     *
     * @return  The minigame definition associated with this minigame. An instance of
                Minigames.Definition.Base or an inherited class.
     */
    function getDefinition ()
    {
        return this.minigameDefinition;
    }
    
    /*
     * Method: update ()
     * Called from a continuous timer, to process things that can't be handled from an event.
     */
    function update ()
    {
        if (this.getState () == Minigames.State.Running)
        {
            if (this.getDefinition ().getTimeLimit () && getElapsedTime () / 1000 >= this.getDefinition ().getTimeLimit ()) 
            {
                // Out of time
                this.endMinigame (Minigames.EndReason.TimeExpired);
            }
        }
        
        else if (this.getState () == Minigames.State.Registering)
        {
            if ((getElapsedTime () / 1000) >= this.getDefinition ().getMaxSignupTime ())
            {
                // Let's start
                this.startMinigame ();
            }            
        }
    }
    
    /*
     * CALLBACKS
     * Below are the callbacks that can be implemented in derived classes.
     * Note that when overloading callbacks, you MUST call the parent class' implementation of the same callback.
     */
    
    /*
     * Method: onUpdate ()
     * Callback method that is called every second, to implement logic that can't
     * be handled from regular events.
     */
    function onUpdate ()
    {
    }
    
    /*
     * Method: onMinigameStateChange ()
     * Callback method that is called when the minigame changes state. For example, when the signup period ends
     * or when the minigame finishes.
     *
     * @param oldState  The old state, a member of the Minigames.State table.
     * @param newState  The old state, a member of the Minigames.State table.
     */
    function onMinigameStateChange (oldState, newState)
    {
    }
    
    /*
     * Method: onPlayerSignUp ()
     * Callback method that is called when a player signs up for the minigame.
     *
     * @param playerid  ID of the player who signed up.
     */
    function onPlayerSignUp (playerid)
    {
    }
    
    /*
     * Method: onPlayerDropOut ()
     * Callback method that is called when a player finishes, or drops out of a minigame.
     *
     * @param playerid  ID of the player who signed out.
     */
    function onPlayerFinish (playerid)
    {
    }
    
    /*
     * Method: onPlayerWasted ()
     * Callback method that is called when a player dies.
     *
     * @param playerid  ID of the player who died
     * @param killerid  ID of the player who killed playerid.
     */   
    function onPlayerWasted (playerid, killerid, killervehicle)
    {
        // Player is out of minigame
    }
   
    /*
     * onPlayerConnect ()
     * blah
     */
    function onPlayerConnect (playerid)
    {
    }
    
    /*
     * Method: onPlayerDisconnect ()
     * Callback method that is called when a player disconnects while in a minigame.
     *
     * @param playerid  The ID of the player that left the server.
     * @param reason  The reason why the player disconnected. 0 = Quit, 1 = crash.
     */
    function onPlayerDisconnect (playerid, reason)
    {
    }
    /*
     * Method: onPlayerStateChange ()
     * Callback method that is called when a player changes state, 
     * i.e. enters or exists a vehicle. 
     *
     * @param playerid  The ID of the player that changed state
     * @param oldstate  The old state
     * @param newstate  The new state
     */  
    function onPlayerStateChange (playerid, oldstate, newstate)
    {
    }
    
    // Data members
    createdVehicles = null;
    joinedPlayers = null;
    playerMinigameStates = null;
    state = Minigames.State.Idle;    
    minigameDefinition = null;
    startTime = null;
    savedPlayerStates = null;
}

/*
 * Class: Minigames.SpawnInfo
 * This class represents a spawn point for a minigame. Every individual spawn point
 * contains information about position, weapons, vehicles, health and armor, allowing
 * for many possibilities.
 */
class Minigames.SpawnInfo 
{
    constructor (spawnPos, rotation = 0)
    {
        this.spawnWeapons = {};
        this.setSpawnPos (spawnPos);
        this.setSpawnRotation (rotation);
        this.setSpawnHealth (200);
        this.setSpawnArmor (100);        
    }
    
    function setSpawnWeapon (wepID, ammo) 
    {
        this.spawnWeapons[wepID] <- ammo;
    }
    
    function setSpawnVehicle (modelID, seatID = 0, c1 = 0, c2 = 0, c3 = 0, c4 = 0)
    {
        this.spawnVehicle = [modelID, seatID, c1, c2, c3, c4];
    }
    
    function setSpawnRotation (rotation)
    {
        this.spawnRotation = rotation;
    }
    
    function setSpawnPos (pos)
    {
        this.spawnPos = clone pos;
    }
    
    function setSpawnHealth (health)
    {
        this.spawnHealth = health;
    }
    
    function setSpawnArmor (armor)
    {
        this.spawnArmor = armor;
    }
    
    function _cloned (orig)
    {
        this.spawnPos = clone orig.spawnPos;
        this.spawnWeapons = clone orig.spawnWeapons;  
        this.spawnVehicle = clone orig.spawnVehicle;
        this.spawnHealth = orig.spawnHealth;
        this.spawnArmor = orig.spawnArmor;
    }
    
    spawnVehicle = null;
    spawnPos = null;
    spawnWeapons = {};
    spawnRotation = 0.0;
    spawnHealth = 200;
    spawnArmor = 100;
}